---
title: "集合類型 - 陣列、字典和集合"
description: "學習 Swift 集合類型：陣列、字典和集合，與 JavaScript 對比"
---

# 集合類型：陣列、字典和集合

在本模組中，我們將探索 Swift 的集合類型，並與 JavaScript 的陣列和物件結構進行對比。Swift 提供了三種主要的集合類型：陣列（Arrays）、字典（Dictionaries）和集合（Sets），每種都具有強類型和強大的函數式程式設計能力。

## 目錄

- [陣列](#陣列)
- [字典](#字典)
- [集合](#集合)
- [集合操作](#集合操作)
- [集合的函數式程式設計](#集合的函數式程式設計)
- [效能考慮](#效能考慮)
- [練習題](#練習題)
- [關鍵要點](#關鍵要點)

## 陣列

Swift 中的陣列是有序的元素集合，所有元素必須具有相同的類型，類似於 JavaScript 陣列，但具有強類型特性。

### 陣列宣告和初始化

<UniversalEditor title="陣列宣告對比" compare={true}>
```javascript !! js
// JavaScript: 動態類型，可以混合不同類型
let numbers = [1, 2, 3, 4, 5];
let mixed = [1, "hello", true, { name: "John" }];

// 建立空陣列
let emptyArray = [];
let arrayWithSize = new Array(5); // 建立包含 5 個 undefined 元素的陣列

// 包含重複值的陣列
let repeated = Array(3).fill("hello");
```

```swift !! swift
// Swift: 強類型，所有元素必須是相同類型
var numbers: [Int] = [1, 2, 3, 4, 5]
var names: [String] = ["Alice", "Bob", "Charlie"]

// 類型推斷
var scores = [85, 92, 78, 96] // Swift 推斷為 [Int]

// 建立空陣列
var emptyArray: [Int] = []
var emptyArray2 = [Int]()

// 包含重複值的陣列
var repeated = Array(repeating: "hello", count: 3)
```
</UniversalEditor>

### 陣列存取和修改

<UniversalEditor title="陣列存取和修改" compare={true}>
```javascript !! js
// JavaScript 陣列存取
let fruits = ["apple", "banana", "orange"];
console.log(fruits[0]); // "apple"
console.log(fruits.length); // 3

// 新增元素
fruits.push("grape"); // 新增到末尾
fruits.unshift("kiwi"); // 新增到開頭
fruits.splice(2, 0, "mango"); // 在索引 2 處插入

// 刪除元素
let last = fruits.pop(); // 刪除並返回最後一個
let first = fruits.shift(); // 刪除並返回第一個
fruits.splice(1, 1); // 刪除索引 1 處的 1 個元素

// 檢查邊界
if (fruits[5]) {
    console.log("元素存在");
} else {
    console.log("索引越界");
}
```

```swift !! swift
// Swift 陣列存取
var fruits = ["apple", "banana", "orange"]
print(fruits[0]) // "apple"
print(fruits.count) // 3

// 新增元素
fruits.append("grape") // 新增到末尾
fruits.insert("kiwi", at: 0) // 在開頭插入
fruits.insert("mango", at: 2) // 在索引 2 處插入

// 刪除元素
let last = fruits.removeLast() // 刪除並返回最後一個
let first = fruits.removeFirst() // 刪除並返回第一個
let removed = fruits.remove(at: 1) // 刪除並返回索引 1 處的元素

// 安全的陣列存取
if fruits.indices.contains(5) {
    print("元素存在: \(fruits[5])")
} else {
    print("索引越界")
}

// 使用 first 和 last 屬性
if let firstFruit = fruits.first {
    print("第一個水果: \(firstFruit)")
}
if let lastFruit = fruits.last {
    print("最後一個水果: \(lastFruit)")
}
```
</UniversalEditor>

### 陣列切片和範圍操作

<UniversalEditor title="陣列切片和範圍操作" compare={true}>
```javascript !! js
// JavaScript 陣列切片
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// 切片 (start, end)
let slice1 = numbers.slice(2, 5); // [3, 4, 5]
let slice2 = numbers.slice(-3); // [8, 9, 10]
let slice3 = numbers.slice(0, -2); // [1, 2, 3, 4, 5, 6, 7, 8]

// 建立範圍
let range = Array.from({length: 5}, (_, i) => i + 1); // [1, 2, 3, 4, 5]
```

```swift !! swift
// Swift 陣列切片
var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

// 使用範圍進行切片
let slice1 = numbers[2..<5] // [3, 4, 5]
let slice2 = numbers[7...] // [8, 9, 10]
let slice3 = numbers[..<8] // [1, 2, 3, 4, 5, 6, 7, 8]

// 建立範圍
let range = Array(1...5) // [1, 2, 3, 4, 5]
let range2 = Array(1..<6) // [1, 2, 3, 4, 5]

// 使用 stride 建立自訂範圍
let stepRange = Array(stride(from: 0, to: 10, by: 2)) // [0, 2, 4, 6, 8]
```
</UniversalEditor>

## 字典

Swift 中的字典是鍵值對集合，類似於 JavaScript 物件，但對鍵和值都有強類型要求。

### 字典宣告和初始化

<UniversalEditor title="字典宣告對比" compare={true}>
```javascript !! js
// JavaScript 物件/字典
let person = {
    name: "John",
    age: 30,
    city: "New York"
};

// 建立空物件
let emptyObject = {};

// 具有計算屬性的物件
let key = "dynamicKey";
let dynamicObject = {
    [key]: "dynamic value",
    staticKey: "static value"
};

// 巢狀物件
let user = {
    profile: {
        name: "Alice",
        email: "alice@example.com"
    },
    settings: {
        theme: "dark",
        notifications: true
    }
};
```

```swift !! swift
// Swift 字典
var person: [String: Any] = [
    "name": "John",
    "age": 30,
    "city": "New York"
]

// 類型安全的字典
var scores: [String: Int] = [
    "Alice": 85,
    "Bob": 92,
    "Charlie": 78
]

// 建立空字典
var emptyDict: [String: Int] = [:]
var emptyDict2 = [String: Int]()

// 具有計算屬性的字典
let key = "dynamicKey"
var dynamicDict: [String: String] = [
    key: "dynamic value",
    "staticKey": "static value"
]

// 巢狀字典
var user: [String: [String: Any]] = [
    "profile": [
        "name": "Alice",
        "email": "alice@example.com"
    ],
    "settings": [
        "theme": "dark",
        "notifications": true
    ]
]
```
</UniversalEditor>

### 字典存取和修改

<UniversalEditor title="字典存取和修改" compare={true}>
```javascript !! js
// JavaScript 物件存取
let person = { name: "John", age: 30 };

// 存取屬性
console.log(person.name); // "John"
console.log(person["age"]); // 30
console.log(person.address); // undefined

// 安全存取（可選鏈）
console.log(person.address?.street); // undefined

// 新增/修改屬性
person.city = "New York";
person["occupation"] = "Developer";

// 刪除屬性
delete person.age;

// 檢查屬性是否存在
if ("name" in person) {
    console.log("姓名存在");
}

// 取得鍵和值
let keys = Object.keys(person);
let values = Object.values(person);
let entries = Object.entries(person);
```

```swift !! swift
// Swift 字典存取
var person: [String: Any] = ["name": "John", "age": 30]

// 存取值
print(person["name"] as? String ?? "Unknown") // "John"
print(person["age"] as? Int ?? 0) // 30

// 安全存取（可選綁定）
if let name = person["name"] as? String {
    print("姓名: \(name)")
}

// 新增/修改值
person["city"] = "New York"
person["occupation"] = "Developer"

// 刪除值
person.removeValue(forKey: "age")
person["age"] = nil // 替代方法

// 檢查鍵是否存在
if person["name"] != nil {
    print("姓名存在")
}

// 取得鍵和值
let keys = Array(person.keys)
let values = Array(person.values)

// 遍歷字典
for (key, value) in person {
    print("\(key): \(value)")
}
```
</UniversalEditor>

## 集合

Swift 中的集合是無序的唯一元素集合，類似於 JavaScript 的 Set，但具有強類型特性。

### 集合宣告和操作

<UniversalEditor title="集合宣告和操作" compare={true}>
```javascript !! js
// JavaScript Set
let numbers = new Set([1, 2, 3, 4, 5]);
let fruits = new Set(["apple", "banana", "orange"]);

// 建立空 Set
let emptySet = new Set();

// 新增元素
numbers.add(6);
fruits.add("grape");

// 刪除元素
numbers.delete(1);
fruits.delete("apple");

// 檢查成員關係
console.log(numbers.has(3)); // true
console.log(fruits.has("mango")); // false

// Set 大小
console.log(numbers.size); // 5

// 轉換為陣列
let numbersArray = Array.from(numbers);
```

```swift !! swift
// Swift Set
var numbers: Set<Int> = [1, 2, 3, 4, 5]
var fruits: Set<String> = ["apple", "banana", "orange"]

// 建立空 Set
var emptySet: Set<Int> = []
var emptySet2 = Set<Int>()

// 新增元素
numbers.insert(6)
fruits.insert("grape")

// 刪除元素
numbers.remove(1)
fruits.remove("apple")

// 檢查成員關係
print(numbers.contains(3)) // true
print(fruits.contains("mango")) // false

// Set 計數
print(numbers.count) // 5

// 轉換為陣列
let numbersArray = Array(numbers)
```
</UniversalEditor>

### 集合操作

<UniversalEditor title="集合操作" compare={true}>
```javascript !! js
// JavaScript Set 操作
let set1 = new Set([1, 2, 3, 4]);
let set2 = new Set([3, 4, 5, 6]);

// 聯集
let union = new Set([...set1, ...set2]);

// 交集
let intersection = new Set(
    [...set1].filter(x => set2.has(x))
);

// 差集
let difference = new Set(
    [...set1].filter(x => !set2.has(x))
);

// 子集檢查
let isSubset = [...set1].every(x => set2.has(x));

// 超集檢查
let isSuperset = [...set2].every(x => set1.has(x));
```

```swift !! swift
// Swift Set 操作
var set1: Set<Int> = [1, 2, 3, 4]
var set2: Set<Int> = [3, 4, 5, 6]

// 聯集
let union = set1.union(set2)

// 交集
let intersection = set1.intersection(set2)

// 差集
let difference = set1.subtracting(set2)

// 對稱差集
let symmetricDiff = set1.symmetricDifference(set2)

// 子集和超集檢查
let isSubset = set1.isSubset(of: set2)
let isSuperset = set1.isSuperset(of: set2)
let isDisjoint = set1.isDisjoint(with: set2)
```
</UniversalEditor>

## 集合操作

Swift 集合提供了強大的函數式程式設計方法，類似於 JavaScript 陣列方法。

### 函數式程式設計方法

<UniversalEditor title="集合的函數式程式設計" compare={true}>
```javascript !! js
// JavaScript 函數式程式設計
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// Map
let doubled = numbers.map(x => x * 2);

// Filter
let evens = numbers.filter(x => x % 2 === 0);

// Reduce
let sum = numbers.reduce((acc, x) => acc + x, 0);

// Find
let firstEven = numbers.find(x => x % 2 === 0);

// Some/Every
let hasEven = numbers.some(x => x % 2 === 0);
let allPositive = numbers.every(x => x > 0);

// FlatMap
let nested = [[1, 2], [3, 4], [5, 6]];
let flattened = nested.flatMap(x => x);

// 鏈式呼叫
let result = numbers
    .filter(x => x % 2 === 0)
    .map(x => x * 2)
    .reduce((acc, x) => acc + x, 0);
```

```swift !! swift
// Swift 函數式程式設計
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

// Map
let doubled = numbers.map { $0 * 2 }

// Filter
let evens = numbers.filter { $0 % 2 == 0 }

// Reduce
let sum = numbers.reduce(0) { $0 + $1 }

// First（相當於 find）
let firstEven = numbers.first { $0 % 2 == 0 }

// Contains（相當於 some）
let hasEven = numbers.contains { $0 % 2 == 0 }
let allPositive = numbers.allSatisfy { $0 > 0 }

// FlatMap（現在 compactMap 用於可選類型，flatMap 用於序列）
let nested = [[1, 2], [3, 4], [5, 6]]
let flattened = nested.flatMap { $0 }

// 鏈式呼叫
let result = numbers
    .filter { $0 % 2 == 0 }
    .map { $0 * 2 }
    .reduce(0) { $0 + $1 }

// 額外的 Swift 方法
let sorted = numbers.sorted()
let reversed = numbers.reversed()
let shuffled = numbers.shuffled()
```
</UniversalEditor>

### 集合效能

<UniversalEditor title="集合效能對比" compare={true}>
```javascript !! js
// JavaScript 集合效能考慮
let array = [1, 2, 3, 4, 5];

// 陣列操作效能
// Push/pop: O(1)
array.push(6);
array.pop();

// Unshift/shift: O(n) - 需要移動所有元素
array.unshift(0);
array.shift();

// 索引存取: O(1)
let element = array[2];

// 搜尋: O(n)
let index = array.indexOf(3);

// 物件屬性存取: O(1) 平均
let obj = { a: 1, b: 2, c: 3 };
let value = obj.a;

// Set 操作: O(1) 平均
let set = new Set([1, 2, 3]);
set.has(2); // O(1) 平均
```

```swift !! swift
// Swift 集合效能考慮
var array = [1, 2, 3, 4, 5]

// 陣列操作效能
// Append/removeLast: O(1) 攤銷
array.append(6)
array.removeLast()

// Insert/remove at beginning: O(n) - 需要移動元素
array.insert(0, at: 0)
array.removeFirst()

// 索引存取: O(1)
let element = array[2]

// 搜尋: O(n)
if let index = array.firstIndex(of: 3) {
    print("在索引處找到: \(index)")
}

// 字典存取: O(1) 平均
var dict: [String: Int] = ["a": 1, "b": 2, "c": 3]
let value = dict["a"]

// Set 操作: O(1) 平均
var set: Set<Int> = [1, 2, 3]
set.contains(2) // O(1) 平均

// Swift 特定優化
// ContiguousArray 用於更好的效能
var fastArray = ContiguousArray<Int>([1, 2, 3, 4, 5])

// 大集合的惰性求值
let lazyResult = numbers.lazy
    .filter { $0 % 2 == 0 }
    .map { $0 * 2 }

// 只在存取時計算
let firstLazyResult = lazyNumbers.first { $0 > 1000 }
```
</UniversalEditor>

## 集合的函數式程式設計

Swift 的集合類型支援強大的函數式程式設計模式。

### 高級函數式操作

<UniversalEditor title="高級函數式操作" compare={true}>
```javascript !! js
// JavaScript 高級函數式程式設計
let students = [
    { name: "Alice", grade: 85, age: 20 },
    { name: "Bob", grade: 92, age: 19 },
    { name: "Charlie", grade: 78, age: 21 },
    { name: "Diana", grade: 95, age: 20 }
];

// 複雜過濾和映射
let topStudents = students
    .filter(student => student.grade >= 90)
    .map(student => ({
        name: student.name,
        grade: student.grade,
        status: "Excellent"
    }));

// 分組
let groupedByAge = students.reduce((groups, student) => {
    const age = student.age;
    if (!groups[age]) groups[age] = [];
    groups[age].push(student);
    return groups;
}, {});

// 多條件排序
let sortedStudents = students.sort((a, b) => {
    if (a.grade !== b.grade) {
        return b.grade - a.grade; // 按成績降序
    }
    return a.name.localeCompare(b.name); // 然後按姓名
});
```

```swift !! swift
// Swift 高級函數式程式設計
struct Student {
    let name: String
    let grade: Int
    let age: Int
}

let students = [
    Student(name: "Alice", grade: 85, age: 20),
    Student(name: "Bob", grade: 92, age: 19),
    Student(name: "Charlie", grade: 78, age: 21),
    Student(name: "Diana", grade: 95, age: 20)
]

// 複雜過濾和映射
let topStudents = students
    .filter { $0.grade >= 90 }
    .map { student in
        (name: student.name, grade: student.grade, status: "Excellent")
    }

// 分組
let groupedByAge = Dictionary(grouping: students) { $0.age }

// 多條件排序
let sortedStudents = students.sorted { first, second in
    if first.grade != second.grade {
        return first.grade > second.grade // 按成績降序
    }
    return first.name < second.name // 然後按姓名
}

// 額外的 Swift 函數式特性
// CompactMap 用於可選類型處理
let optionalNumbers = ["1", "2", "three", "4", "5"]
let validNumbers = optionalNumbers.compactMap { Int($0) }

// Prefix 和 suffix
let firstThree = Array(students.prefix(3))
let lastTwo = Array(students.suffix(2))

// Partition
var mutableStudents = students
let partitionIndex = mutableStudents.partition { $0.grade >= 85 }
let highAchievers = Array(mutableStudents[..<partitionIndex])
let others = Array(mutableStudents[partitionIndex...])
```
</UniversalEditor>

## 效能考慮

理解效能特徵有助於編寫高效的 Swift 程式碼。

### 記憶體和效能優化

<UniversalEditor title="效能優化" compare={true}>
```javascript !! js
// JavaScript 效能考慮
// 陣列效能
let largeArray = new Array(1000000).fill(0);

// 高效的陣列操作
// 對大陣列使用 push/pop 而不是 unshift/shift
let efficientArray = [];
for (let i = 0; i < 1000; i++) {
    efficientArray.push(i); // O(1)
}

// 物件屬性存取優化
let optimizedObject = {};
// 預定義屬性以獲得更好的效能
optimizedObject.prop1 = 1;
optimizedObject.prop2 = 2;

// Set 用於唯一值
let uniqueValues = new Set();
for (let i = 0; i < 1000; i++) {
    uniqueValues.add(i % 100); // 只有 100 個唯一值
}
```

```swift !! swift
// Swift 效能考慮
// 陣列效能
var largeArray = Array(repeating: 0, count: 1_000_000)

// 使用 ContiguousArray 獲得更好的效能
var fastArray = ContiguousArray<Int>()

// 高效的陣列操作
for i in 0..<1000 {
    fastArray.append(i) // O(1) 攤銷
}

// 預分配容量以獲得更好的效能
var optimizedArray = [Int]()
optimizedArray.reserveCapacity(1000) // 預分配記憶體

// 字典優化
var optimizedDict = [String: Int]()
optimizedDict.reserveCapacity(100) // 預分配記憶體

// Set 用於唯一值
var uniqueValues = Set<Int>()
for i in 0..<1000 {
    uniqueValues.insert(i % 100) // 只有 100 個唯一值
}

// 大集合的惰性求值
let lazyNumbers = (1...1_000_000).lazy
    .filter { $0 % 2 == 0 }
    .map { $0 * 2 }

// 只在存取時計算
let firstLazyResult = lazyNumbers.first { $0 > 1000 }
```
</UniversalEditor>

## 練習題

### 練習 1：陣列操作
建立一個函數，接受一個整數陣列，返回一個新陣列，只包含偶數並翻倍。

<UniversalEditor title="練習 1 解答" compare={true}>
```javascript !! js
// JavaScript 解答
function getDoubledEvens(numbers) {
    return numbers
        .filter(num => num % 2 === 0)
        .map(num => num * 2);
}

// 測試
let testNumbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
console.log(getDoubledEvens(testNumbers)); // [4, 8, 12, 16, 20]
```

```swift !! swift
// Swift 解答
func getDoubledEvens(_ numbers: [Int]) -> [Int] {
    return numbers
        .filter { $0 % 2 == 0 }
        .map { $0 * 2 }
}

// 測試
let testNumbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(getDoubledEvens(testNumbers)) // [4, 8, 12, 16, 20]
```
</UniversalEditor>

### 練習 2：字典操作
建立一個函數，統計字串中每個字元的頻率。

<UniversalEditor title="練習 2 解答" compare={true}>
```javascript !! js
// JavaScript 解答
function countCharacters(str) {
    const charCount = {};
    for (let char of str) {
        charCount[char] = (charCount[char] || 0) + 1;
    }
    return charCount;
}

// 測試
console.log(countCharacters("hello")); // { h: 1, e: 1, l: 2, o: 1 }
```

```swift !! swift
// Swift 解答
func countCharacters(_ str: String) -> [Character: Int] {
    var charCount: [Character: Int] = [:]
    for char in str {
        charCount[char, default: 0] += 1
    }
    return charCount
}

// 測試
print(countCharacters("hello")) // ["h": 1, "e": 1, "l": 2, "o": 1]
```
</UniversalEditor>

### 練習 3：集合操作
建立一個函數，找到兩個陣列的交集（共同元素）。

<UniversalEditor title="練習 3 解答" compare={true}>
```javascript !! js
// JavaScript 解答
function findIntersection(arr1, arr2) {
    const set1 = new Set(arr1);
    const set2 = new Set(arr2);
    return [...set1].filter(x => set2.has(x));
}

// 測試
let array1 = [1, 2, 3, 4, 5];
let array2 = [3, 4, 5, 6, 7];
console.log(findIntersection(array1, array2)); // [3, 4, 5]
```

```swift !! swift
// Swift 解答
func findIntersection(_ arr1: [Int], _ arr2: [Int]) -> [Int] {
    let set1 = Set(arr1)
    let set2 = Set(arr2)
    return Array(set1.intersection(set2))
}

// 測試
let array1 = [1, 2, 3, 4, 5]
let array2 = [3, 4, 5, 6, 7]
print(findIntersection(array1, array2)) // [3, 4, 5]
```
</UniversalEditor>

## 關鍵要點

### Swift 集合優勢
1. **類型安全**：所有集合都是強類型的，防止執行時錯誤
2. **效能**：優化的實現，具有可預測的效能特徵
3. **函數式程式設計**：豐富的資料轉換函數式方法
4. **記憶體安全**：使用 ARC 自動記憶體管理
5. **值語義**：陣列和字典是值類型，提供可預測的行為

### 與 JavaScript 的關鍵差異
1. **類型系統**：Swift 集合需要顯式或推斷的類型
2. **可變性**：Swift 區分可變和不可變集合
3. **效能**：Swift 集合具有更可預測的效能特徵
4. **記憶體管理**：自動參考計數 vs 垃圾回收
5. **值類型**：Swift 陣列和字典是值類型，不是參考類型

### 最佳實踐
1. **使用適當的集合類型**來滿足資料需求
2. **利用函數式程式設計方法**進行資料轉換
3. **考慮效能影響**選擇操作
4. **盡可能使用類型推斷**編寫更清晰的程式碼
5. **為大型集合預分配容量**
6. **對大型資料轉換使用惰性求值**

### 下一步
在下一個模組中，我們將探索 Swift 中的控制流，包括條件語句、迴圈和 switch 語句的模式匹配。這將建立在我們對集合的理解基礎上，展示如何在 Swift 中有效地處理資料。 